package com.strato.osgi.scanner.v1_0_0.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;

import com.strato.osgi.scanner.v1_0_0.FrameworkBundleListener;
import com.strato.osgi.scanner.v1_0_0.FrameworkBundleMonitor;

public class DefaultFrameworkBundleMonitor implements FrameworkBundleMonitor{
	
	private List<FrameworkBundleListener> listeners = new ArrayList<FrameworkBundleListener>();
	
	private Object lock = new Object();
	
	public void bundleChanged(BundleEvent e) {
		broadcastEvent(e.getType(),e.getBundle());
	}

	private void broadcastEvent(int eventType,Bundle target) {
		List<FrameworkBundleListener> temp = new ArrayList<FrameworkBundleListener>(listeners.size());
		copyListeners(temp, listeners);
		switch(eventType){
			case BundleEvent.INSTALLED:
				for(Iterator<FrameworkBundleListener> it = temp.iterator();it.hasNext();){
					FrameworkBundleListener listener = (FrameworkBundleListener) it.next();
					listener.onInstall(target);
				}
				break;
			case BundleEvent.RESOLVED:
				for(Iterator<FrameworkBundleListener> it = temp.iterator();it.hasNext();){
					FrameworkBundleListener listener = (FrameworkBundleListener) it.next();
					listener.onResolve(target);
				}
				break;
			case BundleEvent.STARTING:
				for(Iterator<FrameworkBundleListener> it = temp.iterator();it.hasNext();){
					FrameworkBundleListener listener = (FrameworkBundleListener) it.next();
					listener.onStarting(target);
				}
				break;
			case BundleEvent.STOPPING:
				for(Iterator<FrameworkBundleListener> it = temp.iterator();it.hasNext();){
					FrameworkBundleListener listener = (FrameworkBundleListener) it.next();
					listener.onStopping(target);
				}
				break;
			case BundleEvent.STARTED:
				for(Iterator<FrameworkBundleListener> it = temp.iterator();it.hasNext();){
					FrameworkBundleListener listener = (FrameworkBundleListener) it.next();
					listener.onStart(target);
				}
				break;
			case BundleEvent.STOPPED:
				for(Iterator<FrameworkBundleListener> it = temp.iterator();it.hasNext();){
					FrameworkBundleListener listener = (FrameworkBundleListener) it.next();
					listener.onStop(target);
				}
				break;
			case BundleEvent.UNRESOLVED:
				for(Iterator<FrameworkBundleListener> it = temp.iterator();it.hasNext();){
					FrameworkBundleListener listener = (FrameworkBundleListener) it.next();
					listener.onUnresolved(target);
				}
				break;
			default:
				break;// unconcerned
		}		
	}

	private void copyListeners(List<FrameworkBundleListener> dest, List<FrameworkBundleListener> src) {
		synchronized (lock) {
			for(Iterator<FrameworkBundleListener> it = src.iterator();it.hasNext();){
				dest.add(it.next());
			}
		}
	}

	public void addListener(FrameworkBundleListener listener) {
		synchronized (lock) {
			listeners.add(listener);
			Collections.sort(listeners,new Comparator<FrameworkBundleListener>() {
				public int compare(FrameworkBundleListener l1, FrameworkBundleListener l2) {
					return l2.getPriority()-l1.getPriority();
				}
			});
		}
	}

	public void removeListener(FrameworkBundleListener listener) {
		synchronized (lock) {
			listeners.remove(listener);
		}
	}

	public void initialScan(BundleContext context) {
		Bundle[] bundles = context.getBundles();
		for(Bundle bundle:bundles){
			if(bundle.getState()==Bundle.RESOLVED){
				broadcastEvent(BundleEvent.RESOLVED, bundle);
			}else if(bundle.getState()==Bundle.ACTIVE){
				broadcastEvent(BundleEvent.RESOLVED, bundle);
				broadcastEvent(BundleEvent.STARTED, bundle);
			}
		}
	}

}
